﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace BatchDesvPad
{
    public partial class Form2 : Form
    {
        public LGPeWJNM.DataAccessLayer.InstanciaDataset InstanciasDataset { get; set; }

        public System.Threading.Thread tProcessor { get; set; }

        public Form2()
        {
            InitializeComponent();
        }

        private void Form2_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (e.CloseReason == CloseReason.WindowsShutDown || e.CloseReason == CloseReason.ApplicationExitCall || e.CloseReason == CloseReason.TaskManagerClosing)
            {
                this.tpArquivoDeInstancias.CausesValidation = false;
                return;
            }
            switch (MessageBox.Show("Deseja realmente sair?", string.Empty, MessageBoxButtons.YesNo))
            {
                case DialogResult.No:
                    e.Cancel = true;
                    break;
                case DialogResult.Yes:
                    this.tpArquivoDeInstancias.CausesValidation = false;
                    this.tpSelecionarInstâncias.CausesValidation = false;
                    this.tpCriterioDeParada.CausesValidation = false;

                    if (this.tProcessor != null)
                        this.tProcessor.Abort();
                    Application.Exit();
                    break;
            };
        }

        private void bAvancar_Click(object sender, EventArgs e)
        {
            MoveWizardPage(1);
        }

        private void bVoltar_Click(object sender, EventArgs e)
        {
            MoveWizardPage(-1);
        }

        private void MoveWizardPage(int i)
        {
            if (this.tcWizard.TabCount > this.tcWizard.SelectedIndex + i && this.tcWizard.SelectedIndex + i >= 0)
                this.tcWizard.SelectedIndex += i;
        }

        private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            System.Diagnostics.Process.Start("http://www.coin-or.org/SYMPHONY/branchandcut/VRP/data/index.htm");
        }

        private void bOpenFileDialog_Click(object sender, EventArgs e)
        {
            this.openFileDialog.ShowDialog();
        }

        private void openFileDialog_FileOk(object sender, CancelEventArgs e)
        {
            this.tbFileName.Text = this.openFileDialog.FileName;
        }

        private void tpAbrirInstancia_Validating(object sender, CancelEventArgs e)
        {
            try
            {
                this.InstanciasDataset = new LGPeWJNM.DataAccessLayer.InstanciaDataset(this.tbFileName.Text);
                this.dgvInstanciasSelecionadas.BeginInvoke(new MethodInvoker(() =>
                {
                    this.dgvInstanciasSelecionadas.DataSource = this.InstanciasDataset.Where(s => s.Value.Deposito != null).Select(s => new { s.Key.Classe, s.Key.Instancia, s.Value.Otimo }).ToArray();
                }));
            }
            catch (Exception)
            {
                switch (MessageBox.Show("O arquivo parece inválido.", string.Empty, MessageBoxButtons.RetryCancel))
                {
                    case DialogResult.Cancel:
                        e.Cancel = false;
                        break;
                    case DialogResult.Retry:
                        e.Cancel = true;
                        break;
                }
            }
        }

        private void dgvInstanciasSelecionadas_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
        {
            this.dgvInstanciasSelecionadas_ColumnHeaderMouseClick(sender, new DataGridViewCellMouseEventArgs(0, 0, 0, 0, new MouseEventArgs(System.Windows.Forms.MouseButtons.Left, 1, 0, 0, 0)));
        }

        private void dgvInstanciasSelecionadas_ColumnHeaderMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.ColumnIndex == 0)
                foreach (DataGridViewRow item in this.dgvInstanciasSelecionadas.Rows)
                    item.Cells[0].Value = !(bool?)item.Cells[0].Value ?? true;
        }

        private void dgvInstanciasSelecionadas_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            this.cInstancia.BeginInvoke(new MethodInvoker(() =>
            {
                foreach (var serie in cInstancia.Series)
                    serie.Points.Clear();

                var cInst = this.InstanciasDataset[new LGPeWJNM.DataAccessLayer.IdInstancia((string)this.dgvInstanciasSelecionadas["Classe", e.RowIndex].Value, (string)this.dgvInstanciasSelecionadas["Instancia", e.RowIndex].Value)];
                this.cInstancia.Titles[0].Text = (string)this.dgvInstanciasSelecionadas["Instancia", e.RowIndex].Value;
                cInstancia.Series["Deposito"].Points.AddXY(cInst.Deposito.X, cInst.Deposito.Y);
                foreach (var cliente in cInst.Destinos)
                    cInstancia.Series["Clientes"].Points.AddXY(cliente.Coordenada.X, cliente.Coordenada.Y, cliente.Demanda);
            }));
        }

        private void tpSelecionarInstâncias_Validating(object sender, CancelEventArgs e)
        {
            if (this.dgvInstanciasSelecionadas.Rows.Cast<DataGridViewRow>().Count(s => (bool)s.Cells[0].Value) == 0)
            {
                MessageBox.Show("Você não selecionou nenhuma instância, não há com o que continuar", string.Empty, MessageBoxButtons.RetryCancel);
                e.Cancel = true; ;
            }
        }

        #region groupBox lists

        public IEnumerable<Flow.Mediana> Medianas
        {
            get { return FlowElement<Flow.Mediana>(gbMedianas.Controls); }
        }

        public IEnumerable<Flow.Clusterizacao> Clusterizacao
        {
            get { return FlowElement<Flow.Clusterizacao>(gbClusterizacao.Controls); }
        }

        public IEnumerable<Flow.Roteirizacao> Roteirizacao
        {
            get { return FlowElement<Flow.Roteirizacao>(gbRoteirizacao.Controls); }
        }

        public IEnumerable<Flow.Otimizacao> Otimizacao
        {
            get { return FlowElement<Flow.Otimizacao>(gbOtimizacao.Controls); }
        }

        private static IEnumerable<T> FlowElement<T>(System.Windows.Forms.Control.ControlCollection Controls) where T : struct, IConvertible
        {
            foreach (System.Windows.Forms.CheckBox item in Controls)
                if (item.Checked)
                    yield return (T)Enum.Parse(typeof(T), item.Name.Replace("cb", string.Empty));
        }

        private void gbRotina_Validating(object sender, CancelEventArgs e)
        {
            var s = (System.Windows.Forms.GroupBox)sender;
            bool anySelect = false;
            foreach (System.Windows.Forms.CheckBox item in s.Controls)
                anySelect |= item.Checked;
            if (!anySelect)
                ((System.Windows.Forms.CheckBox)s.Controls[s.Controls.Count - 1]).Checked = true;
        }

        #endregion groupBox lists

        private void tpCriterioDeParada_Validating(object sender, CancelEventArgs e)
        {
            if (!this.cbIteracao.Checked && !this.cbBksStop.Checked)
            {
                MessageBox.Show("Não foi escolhido nenhum critério de parada, o que resultaria na execução continua do algorítimo.", string.Empty, MessageBoxButtons.RetryCancel);
                e.Cancel = true;
            }
        }

        private void cbBksStop_CheckedChanged(object sender, EventArgs e)
        {
            this.nBksStop.Enabled = this.cbBksStop.Checked;
        }

        private void cbIteracao_CheckedChanged(object sender, EventArgs e)
        {
            this.nIteracoes.Enabled = this.cbIteracao.Checked;
        }

        private void tbResultadoCompleto_Layout(object sender, LayoutEventArgs e)
        {
            this.tbResultadoCompleto.Text = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), string.Format("Resultados {0:yyyy-MM-dd HH-mm-ss}.xml", System.DateTime.Now));
        }

        private void tbResultadoResumido_Layout(object sender, LayoutEventArgs e)
        {
            this.tbResultadoResumido.Text = System.IO.Path.Combine(System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), string.Format("Resultados {0:yyyy-MM-dd HH-mm-ss} resumido.xml", System.DateTime.Now));
        }

        private void bResultadoCompleto_Click(object sender, EventArgs e)
        {
            this.saveFileDialog.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            this.saveFileDialog.FileName = string.Format("Resultados {0:yyyy-MM-dd HH-mm-ss}.xml", System.DateTime.Now);
        }

        private void bResultadoResumido_Click(object sender, EventArgs e)
        {
            this.saveFileDialog.InitialDirectory = System.Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            this.saveFileDialog.FileName = string.Format("Resultados {0:yyyy-MM-dd HH-mm-ss} resumido.xml", System.DateTime.Now);
        }

        private void tpProcessar_Enter(object sender, EventArgs e)
        {
            this.bAvancar.Enabled = false;
            this.bVoltar.Enabled = false;

            var instancias = (from inst in InstanciasDataset
                              where inst.Value.Deposito != null
                              join DataGridViewRow instChedked2 in this.dgvInstanciasSelecionadas.Rows
                              on new { instancia = inst.Key.Instancia } equals new { instancia = (string)instChedked2.Cells["Instancia"].Value }
                              where (bool)instChedked2.Cells[0].Value
                              select inst).ToDictionary(s => s.Key, s => s.Value);
            var flowPaths = from m in Medianas
                            from c in Clusterizacao
                            from r in Roteirizacao
                            from o in Otimizacao
                            select new Flow.FlowPath()
                            {
                                Mediana = m,
                                Clusterizacao = c,
                                Roteirizacao = r,
                                Otimizacao = o
                            };

            Processor.CompletedInstance += new Processor.Completed(Processor_CompletedInstance);
            Processor.CompletedPath += new Processor.Completed(Processor_CompletedPath);
            Processor.CompletedIteraction += new Processor.Completed(Processor_CompletedIteraction);
            Processor.FoundNewBks += new Processor.Completed(Processor_FoundNewBks);
            Processor.CompletedRoutine += new Processor.Completed(Processor_CompletedRoutine);

            this.pbInstância.Maximum = instancias.Count;
            this.pbAlgoritmo.Maximum = flowPaths.Count();
            this.pbIteracao.Maximum = Convert.ToInt32(this.nIteracoes.Value > this.nBksStop.Value ? this.nIteracoes.Value : this.nBksStop.Value);

            tProcessor = new System.Threading.Thread(new System.Threading.ParameterizedThreadStart(Processor.Routine));
            tProcessor.Start(new Processor.ThreadInput()
            {
                BksStop = this.cbBksStop.Checked ? (int?)Convert.ToInt32(this.nBksStop.Value) : null,
                IteracaoStop = this.cbIteracao.Checked ? (int?)Convert.ToInt32(this.nIteracoes.Value) : null,
                ResultadoCompletoPath = this.cbResultadoCompleto.Checked ? this.tbResultadoCompleto.Text : null,
                ResultadoResumidoPath = this.cbResultadoResumido.Checked ? this.tbResultadoResumido.Text : null,
                FlowPaths = flowPaths,
                Instancias = instancias
            });
        }

        private void Processor_FoundNewBks()
        {
            this.pbIteracao.BeginInvoke(new MethodInvoker(() =>
            {
                this.pbIteracao.Maximum += this.pbIteracao.Value;
            }));
        }

        private void Processor_CompletedRoutine()
        {
            try
            {
                this.BeginInvoke(new MethodInvoker(() =>
                {
                    this.progressBar1.Style = ProgressBarStyle.Continuous;
                    this.bAvancar.Text = "Concluir";
                    this.bAvancar.Click -= new EventHandler(bAvancar_Click);
                    this.bAvancar.Enabled = true;
                    this.bAvancar.Click += new EventHandler(bAvancar_ClickConcluir);
                }));
            }
            catch (InvalidOperationException)
            {
            }
        }

        private void Processor_CompletedIteraction()
        {
            this.pbIteracao.BeginInvoke(new MethodInvoker(() =>
            {
                this.pbIteracao.PerformStep();
            }));
        }

        private void Processor_CompletedPath()
        {
            this.pbAlgoritmo.BeginInvoke(new MethodInvoker(() =>
            {
                this.pbIteracao.Value = 0;
                this.pbIteracao.Maximum = Convert.ToInt32(this.nIteracoes.Value > this.nBksStop.Value ? this.nIteracoes.Value : this.nBksStop.Value);
                this.pbAlgoritmo.PerformStep();
            }));
        }

        private void Processor_CompletedInstance()
        {
            this.pbInstância.BeginInvoke(new MethodInvoker(() =>
            {
                this.pbAlgoritmo.Value = 0;
                this.pbInstância.PerformStep();
            }));
        }

        public void bAvancar_ClickConcluir(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void saveFileDialog_FileOk(object sender, CancelEventArgs e)
        {
        }

        private void bViz_Click(object sender, EventArgs e)
        {
            new viz().ShowDialog();
        }
    }
}